package cn.isjinhao.se.structure.impl;

import cn.isjinhao.se.structure.AbstractRetrieveSupported;
import cn.isjinhao.se.structure.IllegalArgumentException;
import cn.isjinhao.se.structure.StructureException;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @Author ISJINHAO
 * @Date 2021/6/30 17:13
 */
public class Table extends AbstractRetrieveSupported<Tuple, Tuple> {

    private TableMetaInfo tableMetaInfo;

    private final List<Tuple> tupleList = new ArrayList<>();

    public Table(TableMetaInfo tableMetaInfo) {
        for (ColumnMetaInfo columnMetaInfo : tableMetaInfo) {
            if(columnMetaInfo == null || columnMetaInfo.getName() == null) {
                throw new IllegalArgumentException("初始化Table的TableMetaInfo的元素不能为null！");
            }
        }
        this.tableMetaInfo = tableMetaInfo;
    }

    public Table() {
        this.tableMetaInfo = new TableMetaInfo();
    }

    @Override
    public int size() {
        return tupleList.size();
    }

    @Override
    public Tuple get(int index) {
        if (!checkIndexInRange(index)) {
            throw new StructureException("out of range, available range : [" + 0 + ", " + size() + ")");
        }
        return null;
    }

    public void insertItem(List<Object> objectList) {
        if (objectList == null || objectList.size() != tableMetaInfo.size()) {
            throw new StructureException("数据的类型和表的元信息不一致");
        }
        Tuple tuple = new Tuple();
        tuple.setTable(this);
        int i = 0;
        for (ColumnMetaInfo columnMetaInfo : tableMetaInfo) {
            Object o = objectList.get(i);
            if (columnMetaInfo.checkTypeMatch(o)) {
                Cell cell = new Cell(tableMetaInfo.get(i), o);
                tuple.append(cell);
            } else {
                throw new StructureException("数据的类型和表的元信息不一致");
            }
            i++;
        }
        append(tuple);
    }

    public void insertItem(int index, Map<String, Object> itemMap) {
        Tuple tuple = new Tuple();
        for (ColumnMetaInfo columnMetaInfo : tableMetaInfo) {
            Object o = itemMap.get(columnMetaInfo.getName());
            if(o == null) {
                tuple.append(null);
            } else {
                tuple.append(new Cell(o));
            }
        }
        tuple.setTable(this);
        insertItem(index, tuple);
    }

    @Override
    public void insertItem(int index, Tuple tuple) {
        if (!checkIndexCanAdd(index)) {
            throw new StructureException("out of range, available range : [" + 0 + ", " + size() + "]");
        }
        if (tuple == null && index == size()) {
            return;
        }
        if(tuple == null) {
            tupleList.set(index, null);
            return;
        }
        Iterator<Cell> cellIterator = tuple.iterator();
        Iterator<ColumnMetaInfo> columnMetaInfoIterator = tableMetaInfo.iterator();

        int i = 0;
        while(cellIterator.hasNext() && columnMetaInfoIterator.hasNext()) {
            Cell cell = cellIterator.next();
            ColumnMetaInfo columnMetaInfo = columnMetaInfoIterator.next();
            if (!columnMetaInfo.checkTypeMatch(cell)) {
                throw new StructureException("tuple的类型与table的类型不匹配！");
            }
            i++;
        }
        while (cellIterator.hasNext()) {
            cellIterator.next();
            tuple.remove(i);
            i++;
        }
        while (columnMetaInfoIterator.hasNext()) {
            columnMetaInfoIterator.next();
            tuple.append(new Cell(null));
        }
        tuple.setTable(this);
        tupleList.add(index, tuple);
    }

    @Override
    public Tuple removeItem(int index) {
        if (!checkIndexInRange(index)) {
            throw new StructureException("out of range, available range : [" + 0 + ", " + size() + ")");
        }
        return tupleList.remove(index);
    }

    public TableMetaInfo getTableMetaInfo() {
        return tableMetaInfo;
    }

    @Override
    public String toString() {
        if (tableMetaInfo == null || tableMetaInfo.size() == 0) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        sb.append(tableMetaInfo.showColumnAsInLine());
        if (tupleList.isEmpty()) {
            return sb.toString();
        }
        sb.append('\n');
        tupleList.forEach(tuple -> sb.append(tuple).append('\n'));
        return sb.toString();
    }

}
